package org.rcy.framework.data.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

public class FieldReflectUtil {
    public FieldReflectUtil() {
    }

    public static <T> void setFieldValue(T target, String name, Object value) throws Exception {
        if (target == null) {
            throw new IllegalArgumentException("Target must not be null");
        } else {
            Field field = findField(target.getClass(), name);
            makeAccessible(field);
            field.set(target, value);
        }
    }

    public static <T> Object getFieldValue(T target, String name) throws Exception {
        if (target == null) {
            throw new IllegalArgumentException("Target must not be null");
        } else {
            Field field = findField(target.getClass(), name);
            if (field == null) {
                throw new IllegalArgumentException("Can not find field " + name + " from " + target.getClass());
            } else {
                makeAccessible(field);
                return field.get(target);
            }
        }
    }

    public static List<Field> findFields(Class<?> clazz, Class<? extends Annotation> annotationType) {
        List<Field> list = new ArrayList();

        for(Class<?> searchType = clazz; !Object.class.equals(searchType) && searchType != null; searchType = searchType.getSuperclass()) {
            Field[] fields = searchType.getDeclaredFields();
            Field[] var5 = fields;
            int var6 = fields.length;

            for(int var7 = 0; var7 < var6; ++var7) {
                Field field = var5[var7];
                if (field.isAnnotationPresent(annotationType)) {
                    list.add(field);
                }
            }
        }

        return list;
    }

    public static Field findField(Class<?> clazz, String name) {
        return findField(clazz, name, (Class)null);
    }

    public static Field findField(Class<?> clazz, String name, Class<?> type) {
        if (clazz == null) {
            throw new IllegalArgumentException("Class must not be null");
        } else if (name == null && type == null) {
            throw new IllegalArgumentException("Either name or type of the field must be specified");
        } else {
            for(Class<?> searchType = clazz; Object.class != searchType && searchType != null; searchType = searchType.getSuperclass()) {
                Field[] fields = searchType.getDeclaredFields();
                Field[] var5 = fields;
                int var6 = fields.length;

                for(int var7 = 0; var7 < var6; ++var7) {
                    Field field = var5[var7];
                    if ((name == null || name.equals(field.getName())) && (type == null || type.equals(field.getType()))) {
                        return field;
                    }
                }
            }

            return null;
        }
    }

    public static void makeAccessible(Field field) {
        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers()) || Modifier.isFinal(field.getModifiers())) && !field.isAccessible()) {
            field.setAccessible(true);
        }

    }

    public static Class<?> getGenericType(Field field) {
        Type genericType = field.getGenericType();
        if (genericType instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType)genericType;
            Class<?> actualType = (Class)pt.getActualTypeArguments()[0];
            return actualType;
        } else {
            return Object.class;
        }
    }
}
